﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using RepositoryUnit.Data;
using RepositoryUnit.Repository.Interface;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace RepositoryUnit.Repository.UnitOfWork
{
    //public class UnitOfWork<TDbContext> : IUnitOfWork where TDbContext : DbContext
    //{
    //    /// <summary>
    //    /// dbContext上下文
    //    /// </summary>
    //    private readonly TDbContext _dbContext;

    //    /// <summary>
    //    /// 构造函数
    //    /// </summary>
    //    /// <param name="dbContext"></param>
    //    public UnitOfWork(TDbContext dbContext)
    //    {
    //        _dbContext = dbContext;
    //    }

    //    /// <summary>
    //    /// 保存
    //    /// </summary>
    //    public async Task<int> SaveChangesAsync()
    //    {
    //        int code;
    //        try
    //        {
    //            code = await _dbContext.SaveChangesAsync();
    //        }
    //        catch (DbUpdateException e)
    //        {
    //            throw new Exception(e.InnerException == null ? e.Message : e.InnerException.Message);
    //        }
    //        return code;
    //    }
    //}


    public class UnitOfWork<TDbContext> : IUnitOfWork, IDisposable where TDbContext : DbContext
    {
        private readonly TDbContext _dbContext;

        private readonly Dictionary<int, object> _repositoryContainer;
        public UnitOfWork(TDbContext dbContext)
        {
            _dbContext = dbContext;
            _repositoryContainer = new Dictionary<int, object>();
        }

        public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
        {
            var name = typeof(TEntity).FullName.GetHashCode();
            if (!_repositoryContainer.ContainsKey(name))
            {
                _repositoryContainer.Add(name, new EFRepository<TEntity, TDbContext>(_dbContext));
            }

            return _repositoryContainer[name] as IRepository<TEntity>;
        }

        public async Task<int> SaveChangesAsync()
        {
            int num;
            try
            {
                num = await _dbContext.SaveChangesAsync();
            }
            catch (DbUpdateException e)
            {
                Dispose();
                throw new Exception(e.InnerException == null ? e.Message : e.InnerException.Message);
            }
            return num;
        }

        #region Dispose
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool isDispose)
        {
            if (isDispose)
            {
                _dbContext.Dispose();
            }
        }

        #endregion
    }
}